//#include <CGAL/Cartesian.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Point_2.h>
#include <CGAL/Vector_2.h>
#include <CGAL/Line_2.h>
#include <iostream>



//typedef CGAL::Cartesian<double> Rep_class;

typedef double NumberType;
typedef CGAL::Simple_cartesian<NumberType> Kernel;
typedef Kernel::Point_2 Point;
typedef Kernel::Vector_2 Vector;

void test_basic();
void test_orientation();
void test_circle();
void test_centre_of_mass();

void test_list();

void main()
{
	test_list();
	test_circle();
	test_centre_of_mass();
}

void test_basic()
{
	Point p1(1.0, -1.0), p2(4.0, 3.0), p3;
	Vector v1(-1, 10);
	Vector v2(p2 - p1);
	v1 = v1 + v2;
	p3 = p2 + v1 * 2;
	std::cout << "Vector v2: (" << v2.x() << ", " << v2.y() << ")" << std::endl;
	std::cout << "Point p3: (" << p3.x() << ", " << p3.y() << ")" << std::endl;
}

#include <CGAL/predicates_on_points_2.h>
void test_orientation()
{
	using std::cout;
	using std::cin;

	double x1, x2, x3, y1, y2, y3;
	do {
		cout << "Give three points(6 coordinates, separated by spaces).\n";
		cout << ">> " << std::flush;
		cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
		if (!cin)
			break;
		Point p1(x1, y1), p2(x2, y2), p3(x3, y3);
		switch (CGAL::orientation(p1, p2, p3)) {
		case CGAL::LEFT_TURN:
			cout << "Left turn.";
			break;
		case CGAL::RIGHT_TURN:
			cout << "Right turn.";
			break;
		case CGAL::COLLINEAR:
			cout << "The three points lie on a line.";
			break;
		}
		cout << "\n\n";

	} while (true);
}

#include <CGAL/predicates_on_points_2.h>
void test_circle()
{
	Point p1(0, -5), p2(3, -4), p3(4, 3), in(-1, 4), out(5, -1), on(0, 5);
	CGAL::Bounded_side inside, onside, outside;
	inside = CGAL::side_of_bounded_circle(p1, p2, p3, in);
	outside = CGAL::side_of_bounded_circle(p1, p2, p3, out);
	onside = CGAL::side_of_bounded_circle(p1, p2, p3, on);
	assert(inside == CGAL::ON_BOUNDED_SIDE);
	assert(outside == CGAL::ON_UNBOUNDED_SIDE);
	assert(onside == CGAL::ON_BOUNDARY);
}

struct Point_mass {
	Point pos;
	double mass;
	Point_mass(const Point & p, double m) : pos(p), mass(m) {}
	Point_mass(){}
};

Point centre_of_mass(Point_mass *cur, Point_mass *beyond)
{
	Vector sumv(0.0, 0.0);
	double sumw = 0.0;
	for (; cur != beyond; ++cur) {
		sumv = sumv + (cur->pos - CGAL::ORIGIN) * cur->mass;
		sumw += cur->mass;
	}
	return CGAL::ORIGIN + sumv / sumw;
}

void test_centre_of_mass()
{
	const int N = 4;
	Point_mass points[N] = {
		Point_mass(Point(3, 4), 1),
		Point_mass(Point(-3, 5), 1),
		Point_mass(Point(2.1, 0), 10),
		Point_mass(Point(7, -12), 1)
	};
	Point centre = centre_of_mass(points, points + N);
	std::cout << "The centre of mass is: (" << centre.x() << ", " << centre.y() << ")\n";
}

#include <vector>
#include <list>


void write(const Point &centre)
{
	std::cout << "The centre of mass is: ("
		<< centre.x() << ", " << centre.y() << ")\n";
}

template <class Iterator>
Point centre_of_mass(Iterator cur, Iterator beyond)
{
	Vector sumv(0.0, 0.0);
	double sumw = 0.0;
	for (; cur != beyond; ++cur) {
		sumv = sumv + ((*cur).pos - CGAL::ORIGIN) * (*cur).mass;
		sumw += (*cur).mass;

	}
	return CGAL::ORIGIN + sumv / sumw;
}

void test_list()
{
	const int N = 4;
	Point_mass points1[N] = {
		Point_mass(Point(3,4), 1),
		Point_mass(Point(-3,5), 1),
		Point_mass(Point(2.1,0), 10),
		Point_mass(Point(7,-12), 1)
	};
	write(centre_of_mass(points1, points1 + N));

	std::vector<Point_mass> points2(points1, points1 + N);
	write(centre_of_mass(points2.begin(), points2.end()));

	std::list<Point_mass> points3(points1, points1 + N);
	write(centre_of_mass(points3.begin(), points3.end()));
}

#include <CGAL/Polygon_2.h>
typedef CGAL::Polygon_2<Kernel> Polygon;
typedef Polygon::Edge_const_circulator Edge_circulator;

void test_polygon()
{
	Polygon polyg;


	Edge_circulator start = polyg.edges_circulator();
	double perimeter = 0;

	if (start != 0) { // polygon not empty
		Edge_circulator cur = start;
		do {
			//Segment edge = *cur;
			//double l2 = edge.squared_length();
			//perimeter += sqrt(l2);
			++cur;

		} while (cur != start);

	}

	std::cout << "Perimeter of the polygon is "
		<< perimeter << std::endl;
}